這次來看看 rails 的 parameters 為什麼這麼好用?
使用者可以透過三種方法送資料到網頁應用程式。
使用 params。
在你的 controller action 你可以呼叫 params 去存取表單&URL詢問的資料。那 params 到底是什麼?
params 是一個方法會回傳 ActionController::Parameters 物件,在實務上會像一個 hash。假設想從 params 雜湊取得一個值。做法是這樣:
params[:id]
如果存在的話就可以從這裡取得一個值,如果不存在就會是一個 nil。有些事必須要知道,如果是空的就會得到一個空字串。所有在 params 裡的值都是字串,就算是用數字傳送結果也是字串。再對 params 往下挖一點,如果不了解的話那會是一個讓人困惑的問題。
如何做出 form fields & URL parameters 相對應的 params keys?
<form action="/search">
<input name="q" type="text">
<button type="submit">Search</button>
</form>
這是一個簡單的搜尋欄位,會送出一個 POST 請求到 /search。最後的結果你會收到一個 params 物件:
{ "q"=>"", "controller"=>"books", "action"=>"search" }
什麼是 “q”? 這是 html 表單 input 欄位的 name 屬性,name 這裡的名稱可以隨你選。如果用 form_for 建立一個表單,name 會自動產生並且會依照下列模式:
# form_for(@book) with a few fields generates something like this
<form action="/books">
<input type="text" name="book[title]" id="book_title">
<input type="text" name="book[author]" id="book_author">
<input type="text" name="book[cover]" id="book_cover">
<select name="book[language]" id="book_language">
<option value="English">English</option>
<option value="Spanish">Spanish</option>
<option value="French">French</option>
</select>
<button type="submit">Create</button>
</form>
這個 book[title] 在格式在 field names 會產生 params 雜湊,params 雜湊就是 values 放的地方。
{
"book"=>
{
"title"=>"",
"author"=>"",
"cover"=>"",
"language"=>"English"
}
}
使用者送出一個空白表單就會得到這些東西。可以用下面的方法取得資料:
params[:book][:language]
# "English"
params[:book][:author]
# ""
請記住只是像雜湊,但不是一個正規的雜湊,params 可以接受符號跟字串當作當作 keys。意思是說 params["book"] & params[:book] 其實是一樣的。
除了 query parameters,你也可以用 REST-style parameters。在 Rails,稱作這是一個 “dynamic segment”。如果路徑長得像這樣:
get 'books/:id', to: 'books#show'
或
resources :books
就可以像這樣使用 URLs:
/books/1
然後就可以取得 1 ,就是從 books/:id 裡面的 id 取得的。
使用 params
params[:id]
這對使用者找到特定資源非常有幫助。
Book.find(params[:id])
試著將物件儲存到資料庫,但是似乎沒有作用?看看 rails 的 server log。可能會看到:
Unpermitted parameter: :language
這又是什麼意思? Rails 引進了強參數系統 “strong parameters” 在 rails 4 的時候是一個安全性的功能。強迫製作可以儲存的白名單。這可以預防一些問題像是 “mass assignment”,惡意使用者會下 admin = true 指令或是設定其他欄位,但正常狀況下是不會成功的。
可以寫一個白名單像是這樣:
def book_params
params.require(:book).permit(:title, :author, :cover, :language)
end
這是怎麼運作的?
這個 require 方法會去找到 params[:book],如果東西不存在的話會顯示錯誤,而 permit 方法是做出一張被接受的屬性。結果會是得到一個新的 params 雜湊帶著這些屬性,而且已經被清洗乾淨可以準備存進資料庫。
Book.create(book_params)
注意,一般 Ruby 雜湊會繞過這個安全系統。像是這樣:
Book.create(title: "", author: "", cover: "")
如果屬性名稱都是硬編碼那應該沒什麼關係。